package job.handler;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xxl.job.core.handler.annotation.XxlJob;
import core.constants.Constant;
import core.redis.RedisService;
import job.domain.*;
import job.domain.message.Message;
import job.domain.message.MessageText;
import job.domain.message.vo.MessageTextVO;
import job.mapper.CExamMapper;
import job.mapper.MessageTextMapper;
import job.mapper.UserExamMapper;
import job.mapper.UserSubmitMapper;
import job.service.IMessageService;
import job.service.IMessageTextService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class ExamXxlJob {

    @Autowired
    private CExamMapper examMapper;

    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private MessageTextMapper messageTextMapper;

    @Autowired
    private IMessageTextService messageTextService;

    @Autowired
    private IMessageService messageService;

    @Autowired
    private UserExamMapper userExamMapper;
    @XxlJob(value = "examListOrganizeHandler")
    @RequestMapping("/examListOrganizeHandler")
    public void examListOrganizeHandler() {
        log.info("******** examListOrganizeHandler ********");
        List<Exam> ingList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle, Exam::getStartTime, Exam::getEndTime)
                .eq(Exam::getStatus, Constant.TRUE)
                .gt(Exam::getEndTime, LocalDateTime.now()) // 未完成竞赛, 需大于当前时间
                .orderByDesc(Exam::getCreateTime));
        refreshCache(ingList, getIngExamKey());
        List<Exam> edList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle, Exam::getStartTime, Exam::getEndTime)
                .eq(Exam::getStatus, Constant.TRUE)
                .le(Exam::getEndTime, LocalDateTime.now()) // 已完成竞赛, 需小于等于当前时间
                .orderByDesc(Exam::getCreateTime));
        refreshCache(edList, getEdExamKey());

    }

    @XxlJob(value = "topFiveRangeOrganizeHandler")
    @RequestMapping("/topFiveRangeOrganizeHandler")
    public void topFiveRangeOrganizeHandler() {
        log.info("******** topFiveRangeOrganizeHandler ********");
        redisService.deleteObject(Constant.TOP_RANK_LIST);
        List<RankVO> rankVOS = userSubmitMapper.selectTopFiveRank();
        redisService.rightPushAll(Constant.TOP_RANK_LIST, rankVOS);
    }

    @XxlJob("examResultMessageHandler")
    @RequestMapping("/examResultMessageHandler")
    public void examResultMessageHandler(){
        log.info("******** examResultMessageHandler ********");
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime minusDateTime = now.minusDays(1);
        List<Exam> examList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle)
                .eq(Exam::getStatus, Constant.TRUE)
                .ge(Exam::getEndTime, minusDateTime)
                .le(Exam::getEndTime, now));
        if(CollectionUtil.isEmpty(examList)){
            return;
        }
        Set<Long> examIdSet = examList.stream().map(Exam::getExamId).collect(Collectors.toSet());
        List<UserScore> userScoreList = userSubmitMapper.selectUserScoreList(examIdSet);
        if(CollectionUtil.isEmpty(userScoreList)){
            return;
        }
        Map<Long, List<UserScore>> userScoreMap = userScoreList.stream().collect(Collectors.groupingBy(UserScore::getExamId));
        createMessage(examList, userScoreMap);
    }

    private void createMessage(List<Exam> examList, Map<Long, List<UserScore>> userScoreMap) {
        List<MessageText> messageTextList = new ArrayList<>();
        List<Message> messageList = new ArrayList<>();
        for(Exam exam : examList) {
            List<UserScore> userScoreList = userScoreMap.get(exam.getExamId());
            if(CollectionUtil.isEmpty(userScoreList)){
                continue;
            }
            int totalUser = userScoreList.size();
            int rank = 1;
            for(UserScore userScore : userScoreList) {
                String messageTitle = exam.getTitle() + "竞赛排名结果";
                String messageContent = "你参加的竞赛 " + exam.getTitle() + " 已结束, 共有 " + totalUser
                        + " 位用户参加, 你的排名是第 " + rank++ + "名, 得分为 " + userScore.getScore();
                MessageText messageText = new MessageText();
                messageText.setMessageTitle(messageTitle);
                messageText.setMessageContent(messageContent);
                messageText.setCreateBy(Constant.SYSTEM_USER);
                // messageTextMapper.insert(messageText); // 改为批量插入
                messageTextList.add(messageText);

                Message message = new Message();
                message.setSendId(Constant.SYSTEM_USER);
                message.setReceiveId(userScore.getUserId());
                message.setCreateBy(Constant.SYSTEM_USER);
                messageList.add(message);
            }
            userExamMapper.updateUserScoreAndRank(userScoreList);
            redisService.rightPushAll(getExamRankListKey(exam.getExamId()), userScoreList);
        }
        messageTextService.batchInsert(messageTextList);
        Map<String, MessageTextVO> messageTextVOMap = new HashMap<>();
        for(int i = 0; i < messageTextList.size(); i++) {
            MessageText messageText = messageTextList.get(i);
            messageList.get(i).setTextId(messageText.getTextId());
            MessageTextVO messageTextVO = new MessageTextVO();
            messageTextVO.setTextId(messageText.getTextId());
            messageTextVO.setMessageTitle(messageText.getMessageTitle());
            messageTextVO.setMessageContent(messageText.getMessageContent());
            String messageDetailKey = getMessageDetailKey(messageText.getTextId());
            messageTextVOMap.put(messageDetailKey, messageTextVO);
        }
        redisService.multiSet(messageTextVOMap);

        messageService.batchInsert(messageList);
        Map<Long, List<Message>> listMap = messageList.stream().collect(Collectors.groupingBy(Message::getReceiveId));
        Iterator<Map.Entry<Long, List<Message>>> iterator = listMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Long, List<Message>> entry = iterator.next();
            Long userId = entry.getKey();
            String messageListKey = getUserMessageListKey(userId);
            List<Long> textIdList = listMap.get(userId).stream().map(Message::getTextId).toList();
            redisService.rightPushAll(messageListKey, textIdList);
        }
    }



    public void refreshCache(List<Exam> examList, String key) {
        if(CollectionUtil.isEmpty(examList)){
            return;
        }
        Map<String, Exam> examMap = new HashMap<>();
        List<Long> examIdList = new ArrayList<>();
        for (Exam exam : examList) {
            examMap.put(getDetailKey(exam.getExamId()), exam);
            examIdList.add(exam.getExamId());
        }
        redisService.multiSet(examMap);
        redisService.deleteObject(key);
        redisService.rightPushAll(key, examIdList);
    }

    private String getDetailKey(Long examId) {
        return Constant.EXAM_DETAIL_KEY + examId;
    }

    private String getIngExamKey(){
        return Constant.ING_EXAM_LIST_KEY;
    }

    private String getEdExamKey(){
        return Constant.ED_EXAM_LIST_KEY;
    }

    private String getUserMessageListKey(Long userId){
        return Constant.USER_MESSAGE_LIST + userId;
    }

    private String getMessageDetailKey(Long textId){
        return Constant.MESSAGE_DETAIL + textId;
    }

    private String getExamRankListKey(Long examId){
        return Constant.EXAM_RANK_LIST + examId;
    }
}
